/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

extern crate alloc;

use crate::commands::common_command::*;
use crate::common::{ErrorCode, ROOT_SECRET_LEN};
use crate::common::types::RootSecret;
use crate::entry::user_auth_ffi::{CommandId, MAX_CREDENTIAL_NUM_FFI};
use crate::entry::user_auth_ffi::*;
use crate::traits::command_manager::{AccessPolicy, CommandHandler};
use crate::traits::user_db_manager::{UserDbManagerRegistry, Enrolled, CredentialFilter, Credential};
use crate::{impl_command_handler, log_e, log_i, Box, Vec};
use crate::contexts::base_enroll_context::{BaseEnrollContext};
use crate::traits::edit_session_manager::EditSessionManagerRegistry;
use crate::traits::auth_policy_manager::{AuthPolicyManagerRegistry};

// GetUserInfo - implementation
pub type GetUserInfoInput = GetUserInfoInputFfi;

#[derive(Clone, Default)]
pub struct GetUserInfoOutput {
    pub secure_uid: u64,
    pub pin_sub_type: i32,
    pub infos: Vec<EnrolledInfo>,
}

impl TryFrom<GetUserInfoOutput> for GetUserInfoOutputFfi {
    type Error = ErrorCode;

    fn try_from(value: GetUserInfoOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(GetUserInfoOutputFfi {
            secure_uid: value.secure_uid,
            pin_sub_type: value.pin_sub_type,
            infos: value.infos.try_into()?,
        })
    }
}

pub trait GetUserInfoCommandExecutor {
    fn execute(&self, input: GetUserInfoInput) -> Result<GetUserInfoOutput, ErrorCode>;
}

pub struct DefaultGetUserInfoCommandExecutor;

impl GetUserInfoCommandExecutor for DefaultGetUserInfoCommandExecutor {
    fn execute(&self, input: GetUserInfoInput) -> Result<GetUserInfoOutput, ErrorCode> {
        let user_id = input.user_id;
        let secure_uid = UserDbManagerRegistry::get_mut().get_sec_uid(user_id)?;
        let pin_sub_type = UserDbManagerRegistry::get_mut().get_pin_sub_type(user_id)?;
        let enrolled_list = UserDbManagerRegistry::get().get_enrolled_list(user_id)?;
        let enrolled_infos = self.generate_enrolled_infos(enrolled_list);

        let output = GetUserInfoOutput {
            secure_uid: secure_uid,
            pin_sub_type: pin_sub_type as i32,
            infos: enrolled_infos
        };

        Ok(output)
    }
}

impl DefaultGetUserInfoCommandExecutor {
    fn generate_enrolled_infos(&self, enrolled_list: Vec<Enrolled>) -> Vec<EnrolledInfo> {
        let mut credential_infos = Vec::with_capacity(enrolled_list.len());
        
        for enrolled in enrolled_list {
            credential_infos.push(EnrolledInfo {
                enrolled_id: enrolled.enrolled_id,
                auth_type: enrolled.auth_type,
            });
        }
        
        credential_infos
    }
}

impl_command_handler!(
    GetUserInfoCommandHandler,
    GetUserInfoInputFfi,
    GetUserInfoInput,
    GetUserInfoOutputFfi,
    Box<dyn GetUserInfoCommandExecutor>
);

// GetAllUserInfo - implementation
pub type GetAllUserInfoInput = GetAllUserInfoInputFfi;

#[derive(Clone, Default)]
pub struct UserInfo {
    pub secure_uid: u64,
    pub pin_sub_type: i32,
    pub enrolled_infos: Vec<EnrolledInfo>,
}

impl TryFrom<UserInfo> for UserInfoFfi {
    type Error = ErrorCode;
    
    fn try_from(value: UserInfo) -> core::result::Result<Self, ErrorCode> {
        Ok(UserInfoFfi {
            secure_uid: value.secure_uid,
            pin_sub_type: value.pin_sub_type,
            enrolled_infos: value.enrolled_infos.try_into()?,
        })
    }
}

#[derive(Clone, Default)]
pub struct GetAllUserInfoOutput {
    pub user_infos: Vec<UserInfo>,
}

impl TryFrom<Vec<UserInfo>> for UserInfoArrayFfi {
    type Error = ErrorCode;
    
    fn try_from(value: Vec<UserInfo>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = array_from_vec_default::<UserInfo, UserInfoFfi, MAX_USER_NUM_FFI>(value)?;
        Ok(UserInfoArrayFfi {
            data: data,
            len: len,
        })
    }
}

impl TryFrom<GetAllUserInfoOutput> for GetAllUserInfoOutputFfi {
    type Error = ErrorCode;
    
    fn try_from(value: GetAllUserInfoOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(GetAllUserInfoOutputFfi {
            user_infos: value.user_infos.try_into()?,
        })
    }
}

fn get_user_info(user_id: i32) -> Result<UserInfo, ErrorCode> {
    let user = UserDbManagerRegistry::get().get_user(user_id)?;
    let pin_sub_type = UserDbManagerRegistry::get_mut().get_pin_sub_type(user_id)?;
    let enrolled_list = UserDbManagerRegistry::get().get_enrolled_list(user_id)?;

    let mut enrolled_infos = Vec::with_capacity(enrolled_list.len());
    for enrolled in enrolled_list {
        enrolled_infos.push(EnrolledInfo {
            enrolled_id: enrolled.enrolled_id,
            auth_type: enrolled.auth_type,
        });
    }
    
    Ok(UserInfo {
            secure_uid: user.sec_uid,
            pin_sub_type: pin_sub_type as i32,
            enrolled_infos: enrolled_infos,
        })
}

pub trait GetAllUserInfoCommandExecutor {
    fn execute(&self, input: GetAllUserInfoInput) -> Result<GetAllUserInfoOutput, ErrorCode>;
}

pub struct DefaultGetAllUserInfoCommandExecutor;

impl GetAllUserInfoCommandExecutor for DefaultGetAllUserInfoCommandExecutor {
    fn execute(&self, _input: GetAllUserInfoInput) -> Result<GetAllUserInfoOutput, ErrorCode> {
        let mut output = GetAllUserInfoOutput::default();
        let user_ids = UserDbManagerRegistry::get().get_all_user_id()?;
        for user_id in user_ids {
            output.user_infos.push(get_user_info(user_id)?);
        }

        Ok(output)
    }
}

impl_command_handler!(
    GetAllUserInfoCommandHandler,
    GetAllUserInfoInputFfi,
    GetAllUserInfoInput,
    GetAllUserInfoOutputFfi,
    Box<dyn GetAllUserInfoCommandExecutor>
);

// GetAllExtUserInfo - implementation
pub type GetAllExtUserInfoInput = GetAllExtUserInfoInputFfi;

#[derive(Clone, Default)]
pub struct ExtUserInfo {
    pub user_id: i32,
    pub user_info: UserInfo,
}

impl TryFrom<ExtUserInfo> for ExtUserInfoFfi {
    type Error = ErrorCode;
    
    fn try_from(value: ExtUserInfo) -> core::result::Result<Self, ErrorCode> {
        Ok(ExtUserInfoFfi {
            user_id: value.user_id,
            user_info: value.user_info.try_into()?,
        })
    }
}

#[derive(Clone, Default)]
pub struct GetAllExtUserInfoOutput {
    pub user_infos: Vec<ExtUserInfo>,
}

impl TryFrom<Vec<ExtUserInfo>> for ExtUserInfoArrayFfi {
    type Error = ErrorCode;
    
    fn try_from(value: Vec<ExtUserInfo>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = array_from_vec_default::<ExtUserInfo, ExtUserInfoFfi, MAX_USER_NUM_FFI>(value)?;
        Ok(ExtUserInfoArrayFfi {
            data: data,
            len: len,
        })
    }
}

impl TryFrom<GetAllExtUserInfoOutput> for GetAllExtUserInfoOutputFfi {
    type Error = ErrorCode;
    
    fn try_from(value: GetAllExtUserInfoOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(GetAllExtUserInfoOutputFfi {
            user_infos: value.user_infos.try_into()?,
        })
    }
}

pub trait GetAllExtUserInfoCommandExecutor {
    fn execute(&self, input: GetAllExtUserInfoInput) -> Result<GetAllExtUserInfoOutput, ErrorCode>;
}

pub struct DefaultGetAllExtUserInfoCommandExecutor;

impl GetAllExtUserInfoCommandExecutor for DefaultGetAllExtUserInfoCommandExecutor {
    fn execute(
        &self,
        _input: GetAllExtUserInfoInput,
    ) -> Result<GetAllExtUserInfoOutput, ErrorCode> {
        let user_ids = UserDbManagerRegistry::get().get_all_user_id()?;
        let mut output = GetAllExtUserInfoOutput::default();

        output.user_infos.reserve(user_ids.len());
        for user_id in user_ids {
            output.user_infos.push(ExtUserInfo {
                user_id: user_id,
                user_info: get_user_info(user_id)?,
            });
        }

        Ok(output)
    }
}

impl_command_handler!(
    GetAllExtUserInfoCommandHandler,
    GetAllExtUserInfoInputFfi,
    GetAllExtUserInfoInput,
    GetAllExtUserInfoOutputFfi,
    Box<dyn GetAllExtUserInfoCommandExecutor>
);

// DeleteUser - implementation
#[derive(Clone)]
pub struct DeleteUserInput {
    pub user_id: i32,
    pub auth_token: Vec<u8>,
}

impl TryFrom<DeleteUserInputFfi> for DeleteUserInput {
    type Error = ErrorCode;

    fn try_from(value: DeleteUserInputFfi) -> core::result::Result<Self, ErrorCode> {
        Ok(DeleteUserInput {
            user_id: value.user_id,
            auth_token: value.auth_token.try_into()?,
        })
    }
}

#[derive(Clone, Default)]
pub struct DeleteUserOutput {
    pub deleted_infos: Vec<CredentialInfo>,
    pub root_secret: Option<RootSecret>,
}

impl TryFrom<DeleteUserOutput> for DeleteUserOutputFfi {
    type Error = ErrorCode;

    fn try_from(value: DeleteUserOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(DeleteUserOutputFfi {
            deleted_infos: value.deleted_infos.try_into()?,
            root_secret: value.root_secret.try_into()?,
        })
    }
}

fn copy_delete_cred_infos(cred_infos:Vec<&Credential>) -> Vec<CredentialInfo> {
    let mut output: Vec<CredentialInfo> = Vec::new();
    for cred_info in cred_infos {
        let temp: CredentialInfo = CredentialInfo {
            credential_id: cred_info.credential_id,
            executor_index: 0,//todo
            template_id: cred_info.template_id,
            auth_type: cred_info.auth_type,
            executor_matcher: cred_info.executor_matcher,
            executor_sensor_hint: cred_info.executor_sensor_hint,
            auth_sub_type: cred_info.credential_type as i32,
            is_abandoned: false,
            validity_period: 0,//todo
        };
        output.push(temp);
    }
    return output;
}

pub trait DeleteUserCommandExecutor {
    fn execute(&self, input: DeleteUserInput) -> Result<DeleteUserOutput, ErrorCode>;
}

pub struct DefaultDeleteUserCommandExecutor;

impl DeleteUserCommandExecutor for DefaultDeleteUserCommandExecutor {
    fn execute(&self, input: DeleteUserInput) -> Result<DeleteUserOutput, ErrorCode> {
        EditSessionManagerRegistry::get_mut().check_session_valid(input.user_id)?;
        if !BaseEnrollContext::check_cred_change_token(input.user_id, &input.auth_token) {
            log_e!("check token fail");
            return Err(ErrorCode::AuthTokenCheckFailed);
        }

        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == input.user_id &&
            match AuthPolicyManagerRegistry::get().get_auth_policy(cred.auth_type) {
                Err(e) => {
                    log_e!("get_auth_policy fail, ret:{}", e as i32);
                    false
                }
                Ok(value) => value.depends_on_pin(),
            }
        });
        let cred_infos = UserDbManagerRegistry::get().get_credential_list(credential_filter)?;
        for cred in &cred_infos {
            if let Err(err) = UserDbManagerRegistry::get_mut().remove_credential(cred.credential_id) {
                log_e!("delete cred fail, authType:{}, ret:{}", cred.auth_type as i32, err as i32);
                if let Err(e) = UserDbManagerRegistry::get_mut().reload_db() {
                    log_e!("reload fail, ret:{}", e as i32);
                }
                return Err(err);
            }
        }

        //todo
        if !UserDbManagerRegistry::get().check_user_valid(input.user_id)? {
            UserDbManagerRegistry::get_mut().remove_user(input.user_id)?;
        }
        Ok(DeleteUserOutput {
            deleted_infos: copy_delete_cred_infos(cred_infos),
            root_secret: None,
        })
    }
}

impl_command_handler!(
    DeleteUserCommandHandler,
    DeleteUserInputFfi,
    DeleteUserInput,
    DeleteUserOutputFfi,
    Box<dyn DeleteUserCommandExecutor>
);

// EnforceDeleteUser - implementation
pub type EnforceDeleteUserInput = EnforceDeleteUserInputFfi;

#[derive(Clone, Default)]
pub struct EnforceDeleteUserOutput {
    pub deleted_infos: Vec<CredentialInfo>,
}

impl TryFrom<EnforceDeleteUserOutput> for EnforceDeleteUserOutputFfi {
    type Error = ErrorCode;

    fn try_from(value: EnforceDeleteUserOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(EnforceDeleteUserOutputFfi {
            deleted_infos: value.deleted_infos.try_into()?,
        })
    }
}

pub trait EnforceDeleteUserCommandExecutor {
    fn execute(&self, input: EnforceDeleteUserInput) -> Result<EnforceDeleteUserOutput, ErrorCode>;
}

pub struct DefaultEnforceDeleteUserCommandExecutor;

impl EnforceDeleteUserCommandExecutor for DefaultEnforceDeleteUserCommandExecutor {
    fn execute(
        &self,
        _input: EnforceDeleteUserInput,
    ) -> Result<EnforceDeleteUserOutput, ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == _input.user_id
        });
        let credential_infos: Vec<Credential> = UserDbManagerRegistry::get().get_credential_list(credential_filter)?;
        if credential_infos.len() == 0 || credential_infos.len() as usize > MAX_CREDENTIAL_NUM_FFI {
            log_e!("credential_num is error, credential_num: {}", credential_infos.len());
            return Err(ErrorCode::GeneralError);
        }
        UserDbManagerRegistry::get_mut().remove_user(_input.user_id)?;


        Ok(EnforceDeleteUserOutput{deleted_infos: copy_delete_cred_infos(credential_infos)})
    }
}

impl_command_handler!(
    EnforceDeleteUserCommandHandler,
    EnforceDeleteUserInputFfi,
    EnforceDeleteUserInput,
    EnforceDeleteUserOutputFfi,
    Box<dyn EnforceDeleteUserCommandExecutor>
);
